home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / intrvews / acme.lha / acme / src / acme_server / sparcstation.cc < prev    next >
C/C++ Source or Header  |  1992-01-29  |  10KB  |  398 lines

  1. // Copyright (c) 1991 The Regents of the University of California.
  2. // All Rights Reserved.
  3. // The University of California makes no representations about
  4. // the suitability of this software for any purpose.
  5. // It is provided "as is" without express or implied warranty.
  6.  
  7. // SPARCSTATION-DEPENDENT
  8. // (although the same structure can probably be used for other platforms)
  9.  
  10. #define SHOW_AUDIO
  11.  
  12. #include <sys/ioctl.h>
  13. #include <sys/file.h>
  14. #include <signal.h>
  15. #include <fcntl.h>
  16. #include <stropts.h>
  17. #include <errno.h>
  18. #include <stdio.h>
  19. extern "C" {
  20. #include <sys/mman.h>
  21. }
  22. #include "sparcstation.h"
  23. #include "pdev.h"
  24. #include "io.h"
  25. #include "process.h"
  26. #include "synch.h"
  27. #include "scheduler.h"
  28. #include "signals.h"
  29. #include "ldev.h"
  30. #include "fifo.h"
  31. #include "defs.h"
  32. #include "debug.h"
  33.  
  34. LIST pdevs;
  35.  
  36. // AUDIO OUTPUT
  37. // Audio output uses the SunOS 4.1 audio device driver
  38. // and the Sparcstation 1+ built-in speaker
  39.  
  40. // Buffer for accumulating audio output from all audio out ldevs.
  41. // Samples are linear, 12 bit, word aligned
  42. int sum_buf[AUDIO_OUT_BLOCK_SIZE];
  43.  
  44. // output buffer for writes to kernel audio device.
  45. // Samples are mulaw, 8 bit
  46. unsigned char out_buf[AUDIO_OUT_BLOCK_SIZE];
  47.  
  48. BOOLEAN SPARC_AUDIO_OUT::play(LDEV* ldev) {
  49.     MSG_BUF *b = &(ldev->fifo->rbuf);
  50.     int *p, *q;
  51.     int numleft;
  52.     int j;
  53.  
  54.     if (ldev->fifo->get_rbuf(AUDIO_OUT_BLOCK_SIZE << 2, FALSE)) {
  55.     q = sum_buf;
  56.     ldev->update_pdev_time(period);
  57.     numleft = AUDIO_OUT_BLOCK_SIZE << 2;
  58.     while (numleft) {
  59.         p = (int*) b->data;
  60.         numleft -= b->nbytes;
  61.         if (ldev->is_mapped) {
  62.         for (j=0; j<((b->nbytes) >> 2); j++) {
  63.             *q++ += *p++;
  64.         }
  65.         }
  66.         ldev->fifo->read_done();
  67.         if (numleft) ldev->fifo->get_rbuf(numleft, FALSE);
  68.     }
  69.     return TRUE;
  70.     }
  71.     return FALSE;
  72. }
  73.  
  74. BOOLEAN SPARC_AUDIO_OUT::skip(LDEV *ldev) {
  75.     MSG_BUF *b = &(ldev->fifo->rbuf);
  76.     int numleft;
  77.  
  78.     if (ldev->fifo->get_rbuf(AUDIO_OUT_BLOCK_SIZE << 2, FALSE)) {
  79.     ldev->update_pdev_time(period);
  80.     numleft = AUDIO_OUT_BLOCK_SIZE << 2;
  81.     while (numleft) {
  82.         numleft -= b->nbytes;
  83.         ldev->fifo->read_done();
  84.         if (numleft) ldev->fifo->get_rbuf(numleft, FALSE);
  85.     }
  86.     return TRUE;
  87.     }
  88.     return FALSE;
  89. }
  90.  
  91.  
  92. // add together a block of data from all LDevs mapped to the speaker.
  93. // convert it to ulaw, then write it out.
  94. // Then write zero-length buffer for asynchronous interrupt.
  95.  
  96. void SPARC_AUDIO_OUT::output_block(){
  97.     bzero(sum_buf, sizeof(sum_buf));     // prepare sum_buf for accumulation
  98.     call_lts();
  99.  
  100.     // Now we've accumulated all the output.
  101.     // Convert it to mulaw and write it out
  102.  
  103.     unsigned char *r = out_buf;
  104.     int *p = sum_buf;
  105.     for (int i=0; i<AUDIO_OUT_BLOCK_SIZE; i++) {
  106.     *r++ = linear_to_mulaw[(*p++ + 2048) & 4095];
  107.     }
  108. #ifdef SHOW_AUDIO
  109.     *(sparc_video_out->fb_base+data_fd*2) = out_buf[0];
  110.     *(sparc_video_out->fb_base+data_fd*2+1) = 0;
  111. #endif
  112.     write(data_fd, out_buf, AUDIO_OUT_BLOCK_SIZE);
  113.     write(data_fd, out_buf, 0);     // zero length buf to get sigio
  114.  
  115.     update_lts_values();
  116. }
  117.  
  118.  
  119. // The audio out process does the following:
  120. // Initially write two buffers, then sleep, waiting for SIGIO.
  121. // When SIGIO handler finds at least one buffer is done, awaken this process.
  122. // When awakened, write enough blocks so two are pending, then sleep again.
  123.  
  124. void sparc_audio_output(SPARC_AUDIO_OUT *pdev) {
  125.     mask_ints();
  126.     pdev->output_block();
  127.     pdev->output_block();
  128.     for (;;) {
  129.     WHO->deadline = TIMER::current_time + pdev->period;
  130.     pdev->cot.sleep_on();
  131.     while (pdev->left_to_write) {
  132.         pdev->output_block();
  133.         pdev->left_to_write--;
  134.     }
  135.     }
  136. }
  137.  
  138. SPARC_AUDIO_OUT::SPARC_AUDIO_OUT(
  139.     PHYSICAL_SCOPE s,
  140.     MEDIUM m,
  141.     DIRECTION d,
  142.     TIME p,
  143.     float xbar
  144. ) : (s, m, d, p, xbar) {
  145.     if ((data_fd = open(AUDIO_DEVICE, O_WRONLY | O_NDELAY)) < 0)
  146.     PANICERR("audio_out: couldn't open audio output device");
  147.     if (ioctl(data_fd, I_SETSIG, (char*)(S_INPUT|S_OUTPUT|S_MSG)) != 0)
  148.     PANICERR("audio_out: error in I_SETSIG ioctl on device");
  149.     if ((ctl_fd = open(AUDIO_CTL_DEVICE, O_RDWR | O_NDELAY)) < 0)
  150.     PANICERR("audio_out: couldn't open audio control device");
  151.     if (ioctl(ctl_fd, I_SETSIG, (char*)S_MSG) != 0)
  152.     PANICERR("audio_out: error I_SETSIG on pseudo device");
  153.     types << (void*) AUDIO_MULAW_8_8000
  154.     << (void*) AUDIO_MULAW_8_4000;
  155.     left_to_write = 0;
  156. }
  157.  
  158. void init_audio_out() {
  159.     SPARC_AUDIO_OUT* p = new SPARC_AUDIO_OUT(
  160.     WORKSTATION,
  161.     AUDIO,
  162.     OUT,
  163.     (TIME) (double) AUDIO_OUT_BLOCK_SIZE / (double) AUDIO_OUT_SAMPLING_RATE,
  164.         XBAR
  165.     );
  166.     sparc_audio_out = p;
  167.     pdevs << (void*) p;
  168.     SCHEDULER::run(
  169.     new PROCESS(
  170.         (PROCEDURE)sparc_audio_output,
  171.         ARGS() << p,
  172.         TIMER::current_time,
  173.         "audio out"
  174.     )
  175.     );
  176. }
  177.  
  178.  
  179. // AUDIO INPUT
  180. // These variables and functions are for audio input using the SunOS 4.1
  181. // audio device driver and the Sparcstation 1+ built in microphone input.
  182.  
  183. // buffer filled with audio samples by audio device driver.
  184. // samples are mu law, 8 bit
  185. unsigned char in_buf[AUDIO_IN_BLOCK_SIZE];
  186.  
  187. // zero analog value is stored here in mu law encoding
  188. unsigned char mulaw_zero;
  189.  
  190. BOOLEAN SPARC_AUDIO_IN::skip(LDEV *ldev) {
  191.     MSG_BUF *b = &(ldev->fifo->wbuf);
  192.     int numleft;
  193.     unsigned char *p;
  194.     int j;
  195.  
  196.     if (ldev->fifo->get_wbuf(AUDIO_IN_BLOCK_SIZE, FALSE)) {
  197.     ldev->update_pdev_time(period);
  198.     numleft = AUDIO_IN_BLOCK_SIZE;
  199.     while (numleft) {
  200.         numleft -= b->nbytes;
  201.         p = (unsigned char *) b->data;
  202.         for (j=0; j<b->nbytes; j++) {
  203.         *p++ = mulaw_zero;
  204.         }
  205.         ldev->fifo->write_done();
  206.         if (numleft) ldev->fifo->get_wbuf(numleft, FALSE);
  207.     }
  208.     return TRUE;
  209.     }
  210.     return FALSE;
  211. }
  212.  
  213. BOOLEAN SPARC_AUDIO_IN::play(LDEV *ldev) {
  214.     MSG_BUF *b = &(ldev->fifo->wbuf);
  215.     int numleft;
  216.     unsigned char *p, *q;
  217.     int j;
  218.  
  219.     if (ldev->fifo->get_wbuf(AUDIO_IN_BLOCK_SIZE, FALSE)) {
  220.     q = in_buf;
  221.     ldev->update_pdev_time(period);
  222.     numleft = AUDIO_IN_BLOCK_SIZE;
  223.     while (numleft) {
  224.         if (ldev->is_mapped) {
  225.         bcopy(q, b->data, b->nbytes);
  226.         } else {
  227.         p = (unsigned char *) b->data;
  228.         for (j=0; j<b->nbytes; j++) {
  229.             *p++ = mulaw_zero;
  230.         }
  231.         }
  232.         numleft -= b->nbytes;
  233.         q += b->nbytes;
  234.         ldev->fifo->write_done();
  235.         if (numleft) ldev->fifo->get_wbuf(numleft, FALSE);
  236.     }
  237.     return TRUE;
  238.     }
  239.     return FALSE;
  240. }
  241.  
  242. // the audio input process executes this routine
  243. void sparc_audio_input(SPARC_AUDIO_IN* pdev) {
  244.     for (;;) {
  245.     int i = pdev->io->read((char*)in_buf, AUDIO_IN_BLOCK_SIZE, FALSE);
  246.     if (i < 0) PANIC("audio read failed");
  247.     mask_ints();
  248.     pdev->call_lts();
  249.     pdev->update_lts_values();
  250.     WHO->change_deadline(TIMER::current_time + pdev->period);
  251.     unmask_ints();
  252.     }
  253. }
  254.  
  255. SPARC_AUDIO_IN::SPARC_AUDIO_IN (
  256.     PHYSICAL_SCOPE s,
  257.     MEDIUM m,
  258.     DIRECTION d,
  259.     TIME p,
  260.     float xbar
  261. ) : (s, m, d, p, xbar) {
  262.     if ((fd = open(AUDIO_DEVICE, O_RDONLY | O_NDELAY)) < 0)
  263.         PANIC("audio_in: couldn't open audio input device");
  264.     io = new IO(fd);
  265.     mulaw_zero = linear_to_mulaw[2048];
  266.     types << (char*) AUDIO_MULAW_8_8000;
  267. }
  268.  
  269. void init_audio_in() {
  270.     SPARC_AUDIO_IN* p = new SPARC_AUDIO_IN(
  271.     WORKSTATION,
  272.     AUDIO,
  273.     IN,
  274.     (TIME) (double) AUDIO_IN_BLOCK_SIZE / (double) AUDIO_IN_SAMPLING_RATE,
  275.         XBAR
  276.     );
  277.     pdevs << p;
  278.     SCHEDULER::run(
  279.     new PROCESS(
  280.         (PROCEDURE)sparc_audio_input,
  281.         ARGS() << p,
  282.         TIMER::current_time,
  283.         "audio in"
  284.     )
  285.     );
  286. }
  287.  
  288.  
  289. // VIDEO OUTPUT
  290. // Uncompressed monochrome video output
  291. // to the Sparcstation 1 monochrome framebuffer, under SunOS 4.1
  292.  
  293. BOOLEAN SPARC_VIDEO_OUT::play(LDEV *lldev) {
  294.     VIDEO_OUT_LDEV*ldev = (VIDEO_OUT_LDEV*) lldev;
  295.     MSG_BUF *b = &(ldev->fifo->rbuf);
  296.     char* fbp = ldev->base;
  297.     char* fbbase = fbp;
  298.     int nleft = ldev->bytes_line;
  299.     int numleft;
  300.  
  301.     if (ldev->fifo->get_rbuf(ldev->bytes_frame, FALSE)) {
  302.     ldev->update_pdev_time(period);
  303.     numleft = ldev->bytes_frame;
  304.     while (numleft) {
  305.         char* p = b->data;
  306.         int k = b->nbytes;
  307.         if (ldev->is_mapped) {
  308.         while (k) {
  309.             int ncopy = min(nleft, k);
  310.             bcopy(p, fbp, ncopy);
  311.             k -= ncopy;
  312.             nleft -= ncopy;
  313.             p += ncopy;
  314.             fbp += ncopy;
  315.             if (nleft == 0) {
  316.             nleft = ldev->bytes_line;
  317.             fbbase += FB_BYTES_LINE;
  318.             fbp = fbbase;
  319.             }
  320.         }
  321.         }
  322.         numleft -= b->nbytes;
  323.         ldev->fifo->read_done();
  324.         if (numleft) ldev->fifo->get_rbuf(numleft, FALSE);
  325.     }
  326.     return TRUE;
  327.     }
  328.     return FALSE;
  329. }
  330.  
  331. BOOLEAN SPARC_VIDEO_OUT::skip(LDEV *lldev) {
  332.     VIDEO_OUT_LDEV*ldev = (VIDEO_OUT_LDEV*) lldev;
  333.     MSG_BUF *b=&(ldev->fifo->rbuf);
  334.     int numleft;
  335.  
  336.     if (ldev->fifo->get_rbuf(ldev->bytes_frame, FALSE)) {
  337.     ldev->update_pdev_time(period);
  338.     numleft = ldev->bytes_frame;
  339.     while (numleft) {
  340.         numleft -= b->nbytes;
  341.         ldev->fifo->read_done();
  342.         if (numleft) ldev->fifo->get_rbuf(numleft, FALSE);
  343.     }
  344.     return TRUE;
  345.     }
  346.     return FALSE;
  347. }
  348.  
  349.  
  350. // the video output process executes this
  351. void sparc_video_output(SPARC_VIDEO_OUT *pdev) {
  352.     mask_ints();
  353.     for (;;) {
  354.     pdev->call_lts();
  355.     pdev->update_lts_values();
  356.     WHO->deadline += pdev->period;
  357.     pdev->cot.sleep_on();
  358.     }
  359. }
  360.  
  361. SPARC_VIDEO_OUT::SPARC_VIDEO_OUT(
  362.     PHYSICAL_SCOPE s,
  363.     MEDIUM m,
  364.     DIRECTION d,
  365.         TIME p,
  366.     float xbar
  367. ) : (s, m, d, p, xbar) {
  368.     int d = open("/dev/fb", O_RDWR, 0);
  369.     fb_base = mmap(0, 0x20000, PROT_WRITE, MAP_SHARED, d, 0);
  370.     types << (char*) VIDEO_UNC_MONO;
  371. }
  372.  
  373. void init_video_out() {
  374.     SPARC_VIDEO_OUT* p = new SPARC_VIDEO_OUT(
  375.     WORKSTATION,
  376.     VIDEO,
  377.     OUT,
  378.     1.0/VIDEO_FPS,
  379.         XBAR
  380.     );
  381.     sparc_video_out = p;
  382.     pdevs << p;
  383.     SCHEDULER::run(
  384.     p->process = new PROCESS(
  385.         (PROCEDURE)sparc_video_output,
  386.         ARGS() << p,
  387.         TIMER::current_time,
  388.         "video out"
  389.     )
  390.     );
  391. }
  392.  
  393. void init_pdevs() {
  394.     init_audio_out();
  395.     init_audio_in();
  396.     init_video_out();
  397. }
  398.